
#include "../../include/GPCompute.h"

#include <windows.h>
#include <libpngIO.h>
#include <math.h>

#define SCREEN_WIDTH		256		// texture is 256
#define SCREEN_HEIGHT		256		// texture is 256

#define TEXTURE_WIDTH		256
#define TEXTURE_HEIGHT		256

void DoCounter( HWND hWnd ) {
	static DWORD t;
	static LONG count;
	DWORD currtime = GetTickCount();
	if ( t==0 ) t = currtime;
	if ( t + 1000 < currtime ) { static int i;
		static char wndtxt[260], strfps[260];
		if (i==0) { i=1; GetWindowTextA( hWnd, wndtxt, MAX_PATH ); }
		wsprintfA( strfps, "%s FPS:%d", wndtxt, count*1000/(currtime-t) );
		SetWindowTextA( hWnd, strfps );
		t += 1000; count = 0;
	}
	++count;
}

HRESULT LoadShader( LPDWORD* pdwShader, const char* filename )
{
	HANDLE p, f;
	p = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
	if ( INVALID_HANDLE_VALUE == p ) {
		return E_FAIL;
	}
	f = CreateFileMappingA( p, NULL, PAGE_READONLY, 0, 0, NULL );
	if ( NULL == f ) {
		return E_FAIL;
	}
	*pdwShader = (LPDWORD)MapViewOfFile( f, FILE_MAP_READ, 0, 0, 0 );
	if ( NULL == *pdwShader ) {
		return E_FAIL;
	}
	CloseHandle( f );
	CloseHandle( p );
	return S_OK;
}
void UnloadShader( DWORD* pdwShader )
{
	UnmapViewOfFile( (LPCVOID)pdwShader );
}

float wr=0.0f, hr=0.0f;
int dirw=1;
int dirh=1;

#define MOVE	0.02f
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
		case WM_TIMER:
			if ( dirw ) wr += MOVE; else wr -= MOVE;
			if ( wr >= 0.5f ) { dirw = 0; wr = 0.5f; }
			if ( wr <= 0.0f ) { dirw = 1; wr = 0.0f; }

			if ( dirh ) hr += MOVE; else hr -= MOVE;
			if ( hr >= 0.5f ) { dirh = 0; hr = 0.5f; }
			if ( hr <= 0.0f ) { dirh = 1; hr = 0.0f; }
			return 0;

        case WM_DESTROY:
            PostQuitMessage( 0 );
            return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE _1, LPSTR _2, INT cmdShow )
{
	HGPGPU hgpgpu;
	HWND hWnd; GP_CONTEXT ctx; RECT rect = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, };

	// Register the window class
    WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, /*hInst*/NULL, NULL, NULL, NULL, NULL,
                      "GP Tutorial", NULL };
	(void*)(_1, _2);
	wc.hInstance = hInst; 
    RegisterClassExA( &wc );

    // Create the application's window
    hWnd = CreateWindowA( "GP Tutorial", "GP05: GradeEffect",
                      WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                      GetDesktopWindow(), NULL, wc.hInstance, NULL );

	// adjust window size ... 
	AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW, FALSE );
	MoveWindow( hWnd, 300+rect.left, 300+rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );

	// Prepare the context : 
	ctx.width = SCREEN_WIDTH;
	ctx.height = SCREEN_HEIGHT;
	ctx.colortype = TYPE_COLORALPHA;
	ctx.colorprecision = PREC_IN_32;
	ctx.depthtype = TYPE_DEPTH;
	ctx.depthprecision = PREC_IN_16;
	ctx.canvas = (void*)hWnd;

    // Initialize Direct3D
    if( GpComputeInit( &hgpgpu, &ctx, 0 ) >= 0 )
    {
        MSG msg;
		float mpos[] = {
			 0.0f,  0.0f, 0.0f, 0.0f, 
		};

		int ret, i, j; PNGStruct pnginfo;
		void* data; LPBYTE pData, pDataR, pSrc; long pitch;
		HGPARRAY harray1, harray2, harrayt;
		HGPVRRAY hvrray1, hvrray2, hvrrayt; 
		DWORD vshid, pshid; LPDWORD p;
		GP_CALCSTATE state = {0}; 
		GP_RECT rc; HGPSHAPERECT vrc;

		// load resource 
		ret = LoadPNGFileA( "1.png", &pnginfo );
		if ( ret < 0 ) OutputDebugStringA( "Failed Load PNGFile!\n" );

		ret = GpComputeAllocate( hgpgpu, pnginfo.width, pnginfo.height, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &harray1 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate Memory!\n" );
		ret = GpComputeAllocate( hgpgpu, pnginfo.width, pnginfo.height, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &harray2 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate Memory!\n" );

		ret = GpComputeGetPointer( harray1, &data, &pitch );
		if ( ret < 0 ) OutputDebugStringA( "Failed GetPointer!\n" );
		pData = (LPBYTE)data;
		ret = GpComputeGetPointer( harray2, &data, &pitch );
		if ( ret < 0 ) OutputDebugStringA( "Failed GetPointer!\n" );
		pDataR = (LPBYTE)data;

		// copy data to array 
		pSrc = pnginfo.pData;
		for ( i=0; i<pnginfo.height; ++i ) {
		//	memcpy( pData, pSrc, pnginfo.width );
		//	pSrc += pnginfo.width; pData += pitch;
			for ( j=0; j<pnginfo.width; ++j ) {
				unsigned long n = *((DWORD*)pSrc+j);
			//	A R G B				 // A B G R
				unsigned long v = ((n&0xFF000000))|((n&0x00FF0000)>>16)|((n&0x0000FF00))|((n&0x000000FF)<<16);
				*((DWORD*)pData+j) = 0xFFFFFFFF - v;
				*((DWORD*)pDataR+j) = v;
			}
			pSrc += pnginfo.width*sizeof(DWORD), pData += pitch, pDataR += pitch;
		}
		FreePNGFile( &pnginfo );

		// prepare sin table : 
		ret = GpComputeAllocate( hgpgpu, TEXTURE_WIDTH, 1, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &harrayt );
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate Memory!\n" );

		ret = GpComputeGetPointer( harrayt, &data, &pitch );
		if ( ret < 0 ) OutputDebugStringA( "Failed GetPointer!\n" );

		pData = (LPBYTE)data;
		for ( j=0; j<TEXTURE_WIDTH/2; ++j ) {
			float f = sinf( j * 2.0f * 3.1416f / TEXTURE_WIDTH );
		//	A R G B				 // A B G R
			*(LPDWORD)pData = (DWORD)(0xFFFFFF * f); pData += 4;
		}
		// zero the left data : 
		memset( pData, 0x00, TEXTURE_WIDTH/2 ); 

		// vertex prepare 
		rc.pt1.x = -1.0f, rc.pt1.y =  1.0f;
		rc.pt2.x =  1.0f, rc.pt2.y = -1.0f;
		ret = GpComputeShapeRect( hgpgpu, &rc, 1, &vrc );
		if ( ret < 0 ) OutputDebugStringA( "Failed Create Vertex Rectangle!\n" );
		ret = GpComputeSelectSourceShape( hgpgpu, vrc );
		if ( ret < 0 ) OutputDebugStringA( "Failed SetStreamSource and Index!\n" );

		// texture prepare 
		ret = GpComputeAllocateVram( hgpgpu, TEXTURE_WIDTH, TEXTURE_HEIGHT, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &hvrray1 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate VideoMemory 1!\n" );
		ret = GpComputeAllocateVram( hgpgpu, TEXTURE_WIDTH, TEXTURE_HEIGHT, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &hvrray2 ); // middle ... 
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate VideoMemory 2!\n" );
		ret = GpComputeAllocateVram( hgpgpu, TEXTURE_WIDTH, 1, 
			TYPE_COLORALPHA, PREC_IN_32, OPMODE_READ, &hvrrayt ); // middle ... 
		if ( ret < 0 ) OutputDebugStringA( "Failed Allocate VideoMemory t!\n" );

		ret = GpComputeSubmit( hgpgpu, harray1, hvrray1, 0, 0 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Submit VideoMemory!\n" );
		ret = GpComputeSubmit( hgpgpu, harray2, hvrray2, 0, 0 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Submit VideoMemory!\n" );
		ret = GpComputeSubmit( hgpgpu, harrayt, hvrrayt, 0, 0 );
		if ( ret < 0 ) OutputDebugStringA( "Failed Submit Videomemory!\n" );

		// shader programe 
		if (FAILED(LoadShader( &p, "GPComputeGrade2.vso" ))) 
			OutputDebugStringA( "Failed Allocate Load VertexShader!\n" );
		ret = GpComputeCreateProgram( hgpgpu, PROGRAM_VERTEX, &vshid, p );
		if ( ret < 0 ) OutputDebugStringA( "Failed Create VertexShader!\n" );
		UnloadShader( p );
		ret = GpComputeSelectProgram( hgpgpu, PROGRAM_VERTEX, vshid );
		if ( ret < 0 ) OutputDebugStringA( "Failed Select VertexShader!\n" );

		if (FAILED(LoadShader( &p, "GPComputeGrade2.pso" )))
			OutputDebugStringA( "Failed Allocate Load PixelShader" );
		ret = GpComputeCreateProgram( hgpgpu, PROGRAM_PIXEL, &pshid, p );
		if ( ret < 0 ) OutputDebugStringA( "Failed Create PixelShader!\n" );
		UnloadShader( p );
		ret = GpComputeSelectProgram( hgpgpu, PROGRAM_PIXEL, pshid );
		if ( ret < 0 ) OutputDebugStringA( "Failed Select PixelShader!\n" );

		ret = GpComputeSelectSourceUnit( hgpgpu, hvrrayt, 0 ); 
		if ( ret < 0 ) OutputDebugStringA( "Failed SetTexture!\n" );
		ret = GpComputeSelectSourceUnit( hgpgpu, hvrray1, 1 ); 
		if ( ret < 0 ) OutputDebugStringA( "Failed SetTexture!\n" );
		ret = GpComputeSelectSourceUnit( hgpgpu, hvrray2, 2 ); 
		if ( ret < 0 ) OutputDebugStringA( "Failed SetTexture!\n" );

		// render state : 
		state.red_write = state.green_write = state.blue_write = 1;
		ret = GpComputeSetProp( hgpgpu, &state );
		if ( ret < 0 ) OutputDebugStringA( "Failed Set RenderState!\n" );

		// Show the window
		ShowWindow( hWnd, cmdShow );
		UpdateWindow( hWnd );

        // Enter the message loop
        ZeroMemory( &msg, sizeof(msg) );

		SetTimer( hWnd, 0, 40, NULL );
        while( msg.message!=WM_QUIT )
        {
            if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
            {
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            }
            else
            {
				GP_PREPARE prepare = {0};
				DoCounter( hWnd );
				// RENDER 

				// pixel prepare : 
				mpos[0] = wr;
				GpComputeSetConstants( hgpgpu, PROGRAM_PIXEL, 0, mpos, 1 ); // position

				ret = GpComputeBeginTarget( hgpgpu, NULL, &prepare ); // RTT
				if ( ret < 0 ) OutputDebugStringA( "Failed BeginScene!\n" );
				ret = GpComputeCalculateRect( hgpgpu, 0, 0, NULL ); // draw all 
				if ( ret < 0 ) OutputDebugStringA( "Failed RenderToTexture!\n" );
				ret = GpComputeEndTarget( hgpgpu, 1 );
				if ( ret < 0 ) OutputDebugStringA( "Failed EndScene!\n" );
            }
        }
		KillTimer( hWnd, 0 );

		GpComputeDeleteProgram( hgpgpu, PROGRAM_PIXEL, pshid );
		GpComputeDeleteProgram( hgpgpu, PROGRAM_VERTEX, vshid );
		
		GpComputeDeallocateVram( hgpgpu, hvrrayt );
		GpComputeDeallocateVram( hgpgpu, hvrray2 );
		GpComputeDeallocateVram( hgpgpu, hvrray1 );
		GpComputeDeallocate( hgpgpu, harray1 );
		GpComputeDeallocate( hgpgpu, harray2 );
		GpComputeDeallocate( hgpgpu, harrayt );

		GpComputeShapeFree( hgpgpu, vrc );

		GpComputeFree( hgpgpu );
    }

	DestroyWindow( hWnd );
    // Clean up everything and exit the app
    UnregisterClassA( "GP Tutorial", wc.hInstance );
    return 0;
}
